<template>
  <div class="cateParams_container">
    <!-- <h3>这是分类参数CateParams子组件</h3> -->
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>分类参数</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- card---卡片视图 -->
    <el-card class="box-card">
      <!-- 警告条 使用了一个新组件 el-alert
      :closable="false" 去掉关闭x
      show-icon带图标
      -->
      <el-alert title="注意：只允许为第三级分类设置相关参数！" type="warning" :closable="false" show-icon> </el-alert>
      <!-- 选择商品分类区域 -->
      <el-row class="cat-opt">
        <el-col class="col_left">
          <!-- 将选择商品分类的span和el-cascader写在一个el-col中，避免级联选择器水平方向位置发生改变 -->
          <span>选择商品分类：</span>
          <!-- 级联选择器 -->
          <!-- BUG:3 当选择完一个三级分类后，tabs标签动态参数和静态属性中的表格，都渲染完成。然而，当选择了一个
          一级分类或者二级分类时，在change事件handleChange中，将   this.selectedCateKeys = [];级联选择框回到了默认
          的“请选择”的初始状态，但是tabs标签下表格数据还在，而且还能进行操作，然后【操作】或
          【删除】按钮的三级分类id,已经不能使用了。因此，表格数据也不能存在 -->
          <el-cascader v-model="selectedCateKeys" :options="goodsCateList" :props="configItem" @change="handleChange" clearable></el-cascader>
        </el-col>
      </el-row>
      <el-tabs v-model="activeName" @tab-click="handleTabClick">
        <!-- 添加 动态参数 的面板 -->
        <!-- 结合API接口文档，many代表动态参数,name属性值定义activeName值，
        只有两个el-tab-pane表示activeName只能娶到many和only两个值 -->
        <el-tab-pane label="动态参数" name="many">
          <el-row class="para_attr">
            <el-col :span="1">
              <el-button type="primary" :disabled="flag" size="mini" @click="addManyAndOnly">
                添加参数
              </el-button>
            </el-col>
          </el-row>
          <!-- 动态参数列表 -->
          <el-table :data="manyTableData" stripe border style="width: 100%">
            <!-- 展开列 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                {{ scope.row }}
                <!-- 村换tag标签 -->
                <!--getParamsData方法中输出的res.data是表格数据，scoped.row取当前行  -->
                <!-- BUG1：新添加的动态参数和静态属性中，都会生成一个空白的tag标签
                ''.split(' ') 会得到一个有一个空字符串的元素的数组 [''] -->
                <!-- BUG2:如果渲染的每一行数据，都共用下面el-input中的inputVisible和
                inputValue,则表格渲染时，每一行渲染new Tag毫无差别，操作表格中任意一行，其他行
                都会发生联动。为此，需要为每一行生成自己的inputValue和inputVisible,在getParamsData()
                中继续对res.data进行处理，为遍历数组res.data中的每一个项item，添加inputValue和
                inputVisible属性。之后，将初始值inputVisible替换成scope.row.inputVisible,inputValue同理-->
                <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" @close="handleClose(i, scope.row)" closable>
                  {{ item }}
                </el-tag>
                <!-- button按钮和输入文本框切换的组件 -->
                <!-- 你可能想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native；
                通俗点讲：就是在父组件中给子组件绑定一个原生的事件，就将子组件变成了普通的HTML标签，不加
                '. native'事件是无法触发的。el-input就是element ui库自定义组件 -->
                <el-input
                  class="input-new-tag"
                  v-if="scope.row.inputVisible"
                  v-model="scope.row.inputValue"
                  ref="saveTagInput"
                  size="small"
                  @keyup.enter.native="handleInputConfirm(scope.row)"
                  @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index" label="#"></el-table-column>
            <el-table-column prop="attr_name" label="参数名称"> </el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <!-- {{ scope.row }} -->
                <el-button type="primary" size="mini" icon="el-icon-edit" @click="showEditDialog(scope.row.cat_id, scope.row.attr_id)">
                  编辑
                </el-button>
                <el-button type="danger" size="mini" icon="el-icon-delete" @click="deleteData(scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <!-- 添加 静态属性 的面板 -->
        <!-- 结合API接口文档，only代表静态属性 -->
        <el-tab-pane label="静态属性" name="only">
          <el-row class="para_attr">
            <el-col :span="1"><el-button type="primary" :disabled="flag" size="mini" @click="addManyAndOnly">添加属性</el-button> </el-col>
          </el-row>
          <!-- 静态属性表格 -->
          <el-table :data="onlyTableData" stripe border style="width: 100%">
            <!-- 展开列 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" closable>
                  {{ item }}
                </el-tag>
                <!-- button按钮和输入文本框切换的组件 -->
                <el-input
                  class="input-new-tag"
                  v-if="scope.row.inputVisible"
                  v-model="scope.row.inputValue"
                  ref="saveTagInput"
                  size="small"
                  @keyup.enter.native="handleInputConfirm(scope.row)"
                  @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index" label="#"></el-table-column>
            <el-table-column prop="attr_name" label="属性名称"> </el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <!-- {{ scope.row }} -->
                <el-button type="primary" size="mini" icon="el-icon-edit" @click="showEditDialog(scope.row.cat_id, scope.row.attr_id)">编辑</el-button>
                <el-button type="danger" size="mini" icon="el-icon-delete" @click="deleteData(scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <!-- 对话框，由于添加动态参数和静态属性的对话框view视图基本一样，共用一个对话框 -->
    <!-- 对话框的标题不同，使用计算属性实时计算获得 -->
    <el-dialog :title="'添加' + titleText" :visible.sync="addDialogVisible" width="50%" @close="resetDialogForm">
      <!-- 动态参数或静态属性的表单验证 -->
      <el-form :model="AddRuleForm" :rules="addAndEditRules" ref="addFormRef" label-width="100px">
        <el-form-item :label="titleText" prop="attr_name">
          <el-input v-model="AddRuleForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addDataPre">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 动态参数和静态属性表格中,编辑按钮点击，弹出一个对话框，view视图基本类似，共用一个对话框 -->
    <el-dialog :title="'修改' + titleText" :visible.sync="editDialogVisible" width="50%" @close="resetEditDialog">
      <!-- 动态参数或静态属性表格中“编辑”按钮弹出对话框 -->
      <el-form :model="editRuleForm" :rules="addAndEditRules" ref="editFormRef" label-width="100px">
        <el-form-item :label="titleText" prop="attr_name">
          <el-input v-model="editRuleForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editFormPre">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    const messageInfo = (rule, value, cb) => {
      // console.log(this.activeName === 'many');
      console.log(typeof value);
      // 切记：在element ui中，如果设定自定义校验规则。表单域中内容为空，则用undefined表示
      if (value === undefined) {
        if (this.activeName === 'many') {
          return cb(new Error('请输入动态参数'));
        } else return cb(new Error('请输入静态属性'));
      } else if (value === '') {
        if (this.activeName === 'many') {
          return cb(new Error('请输入动态参数'));
        } else return cb(new Error('请输入静态属性'));
      } else {
        return cb();
      }
    };
    return {
      // 商品分类，级联选择框使用
      goodsCateList: [],
      // el-cascade的配置选项
      configItem: {
        expandTrigger: 'hover',
        label: 'cat_name',
        value: 'cat_id',
        children: 'children'
      },
      // 分类的一、二、三级id，如果缺少二级或者三级id，则不能直接加参数。警示框中已经说明只能为第三极分类添加参数
      selectedCateKeys: [],
      // Tabs标签页组件的默认选中
      activeName: 'many',
      // 添加参数 和 添加属性 按钮的禁用状态与否
      // flag: true,
      // 动态参数数据源-数组
      manyTableData: [],
      // 静态属性数据源-数组
      onlyTableData: [],
      // 添加动态参数和静态属性弹出对话框的状态码
      addDialogVisible: false,
      // 动态参数和静态属性表格中，点击“编辑”按钮弹出对话框状态码
      editDialogVisible: false,
      // 对话框表单数据源对象
      AddRuleForm: {},
      addAndEditRules: {
        attr_name: [
          /*
          自定义校验规则：如果在动态参数对话框，没有输入任何内容，校验中value是undefind,而不是空字符串，提示“请输入动态参数”
          自定义校验规则：如果在静态对话框，没有输入任何内容，校验中value是undefind,而不是空字符串，提示“请输入静态属性”
          */
          { validator: messageInfo, trigger: 'blur' },
          { min: 1, max: 15, message: '长度在 1 到 15 个字符', trigger: 'blur' }
        ]
      },
      // 添加 动态参数 和 静态属性 表格中，编辑按钮弹出对话框中表单数据源
      editRuleForm: {}
      // 展开扩展列时，显示按钮和输入文本框之一的状态码，默认false,表示默认显示按钮
      // inputVisible: false,
      // // 展开扩展列时，new Tag新建的tag的文本值
      // inputValue: ''
    };
  },
  // a.watch侦听属性---需要在data中声明flag
  // watch: {
  //   // 监听selectedCateKeys属性
  //   selectedCateKeys(val) {
  //     this.flag = val.length === 3 ? false : true;
  //   }
  // },
  // b.computed计算属性---使用计算属性，不需要在data中额外声明flag变量
  computed: {
    // 绑定在添加属性和添加参数按钮的disabled属性的属性值flag
    flag() {
      if (this.selectedCateKeys.length !== 3) {
        return true;
      }
      return false;
    },
    // 计算级联框中选中的第三级分类的id
    catId() {
      if (this.selectedCateKeys.length === 3) {
        return this.selectedCateKeys[2];
      }
      // 如果没有选中第三级分类，返回一个null
      return null;
    },
    titleText() {
      if (this.activeName === 'many') {
        return '动态参数';
      }
      return '静态属性';
    }
  },
  created() {
    this.getShopCate();
  },
  methods: {
    // 获取所有商品分类数据
    async getShopCate() {
      // type:3,表示要显示三层分类列表
      const { data: res } = await this.$http.get('categories', {
        params: { type: 3 }
      });
      console.log(res);
      // 获取所有级别分类失败
      if (res.meta.status !== 200) {
        return this.$message.error('获取商品分类列表失败!');
      }
      // 获取所有级别分类成功
      this.goodsCateList = res.data;
    },
    async handleChange() {
      /*
      1.selectedCateKeys数组的长度，决定了选择了几级分类
      2.已经声明只为第三级分类添加参数，则需要数组的长度为3
      3.如果选择到一级、二级分类，将数组元素清空，.selectedCateKeys=[]，对应级联选择框的默认选择状态
      */
      console.log(this.selectedCateKeys);
      if (this.selectedCateKeys.length !== 3) {
        this.selectedCateKeys = [];
        //  BUG:3 当选择完一个三级分类后，tabs标签动态参数和静态属性中的表格，都渲染完成。然而，当选择了一个
        //  一级分类或者二级分类时，在change事件handleChange中，将   this.selectedCateKeys = [];级联选择框回到了默认
        //  的“请选择”的初始状态，但是tabs标签下表格数据还在，而且还能进行操作，然后【操作】或
        //  【删除】按钮的三级分类id,已经不能使用了。因此，表格数据也不能存在
        // 解决：也要清空动态参数和静态属性数据源数组
        this.manyTableData = [];
        this.onlyTableData = [];
        return;
      }
      // 选择了三级分类,就可以发起“动态参数”和“静态属性”数据的请求,获取 参数列表
      // 选择级联选择框和切换tab页都要调用下面的请求，以获取参数列表。为此，将下面代码抽离出来，定义
      // 函数getParamsData()
      // const { data: res } = await this.$http.get(
      //   `categories/${this.catId}/attributes`,
      //   {
      //     params: { sel: this.activeName }
      //   }
      // );
      // console.log(res);
      // if (res.meta.status !== 200)
      //   return this.$message.error('请求参数列表失败!');
      // // 请求参数列表成功
      // console.log(res.data);
      this.getParamsData();
    },
    // tabs标签页的点击事件
    handleTabClick() {
      // 标签页切换时，this.activeName的值，在many和only之间变化
      console.log(this.activeName);
      // 调用getParamsData()方法拿到动态参数或静态属性数据
      this.getParamsData();
    },
    async getParamsData() {
      // activeName默认值为"many"
      const { data: res } = await this.$http.get(`categories/${this.catId}/attributes`, {
        params: { sel: this.activeName }
      });
      console.log(res);
      if (res.meta.status !== 200) {
        return this.$message.error('请求参数列表失败!');
      }
      // 请求参数列表成功，res.data的含义是动态参数名称或者静态属性名称
      // console.log(res.data);
      // res.data数组中每一项的attr_vals属性是一个字符串，内部以空格隔开多个动态参数或者属性，使用String的Split方法分割字符串，拿到
      // 动态参数或者静态属性的字符串
      // 1. 对res.data数组进行处理，将其中的每一个item项的attr_vals属性，属性值字符串转化为数组
      res.data.forEach(item => {
        // 2. item.attr_vals.Split(' ')，返回值是每一个分割部分组成的数组，把它再赋给该项的attr_vals属性
        // 3.  BUG1解决：新添加的动态参数和静态属性中，都会生成一个空白的tag标签
        // ''.split(' ') 会得到一个有一个空字符串的元素的数组 ['']；区别：''.split('')=[]
        // 4. 场景新添加的参数，item.attr_vals 为  '',让item.attr_vals=[]而非['']
        item.attr_vals = item.attr_vals !== '' ? item.attr_vals.split(' ') : [];
        // 5.BUG2:如果渲染的每一行数据，都共用下面el-input中的inputVisible和
        // inputValue,则表格渲染时，每一行渲染new Tag毫无差别，操作表格中任意一行，其他行
        // 都会发生联动。为此，需要为每一行生成自己的inputValue和inputVisible,在getParamsData()
        // 中继续对res.data进行处理，为遍历数组res.data中的每一个项item，添加inputValue和
        // inputVisible属性。之后，将初始值inputVisible替换成scope.row.inputVisible,inputValue同理
        // 添加属性：文本框输入值，默认为''
        item.inputValue = '';
        // 添加属性：默认显示状态
        item.inputVisible = false;
      });
      console.log(res.data);
      /*
      动态参数和静态属性数据源不同，那么拿到的这份数据res.data到底属于谁呢？要做选择分支判断
      */
      if (this.activeName === 'many') {
        this.manyTableData = res.data;
      } else {
        this.onlyTableData = res.data;
      }
    },
    // 添加动态参数和静态属性按钮的点击事件
    addManyAndOnly() {
      // 弹出对话框
      this.addDialogVisible = true;
    },
    // 点击对话框确定按钮的事件
    addDataPre() {
      // 1. 预校验表单
      this.$refs.addFormRef.validate(async valid => {
        if (!valid) return;
        // 2. 预校验通过，开始post数据请求
        const { data: res } = await this.$http.post(`categories/${this.catId}/attributes`, {
          attr_name: this.AddRuleForm.attr_name,
          attr_sel: this.activeName
        });
        console.log(res);
        if (res.meta.status !== 201) {
          return this.$message.error('添加' + this.titleText + '失败!');
        }
        // 3.添加成功的提示
        this.$message.success('添加' + this.titleText + '成功!');
        // 4.关闭对话框
        this.addDialogVisible = false;
        // 5.重新刷新分类参数和动态属性列表
        this.getParamsData();
      });
    },
    // 对话框关闭的事件
    resetDialogForm() {
      // 清空表单域
      this.$refs.addFormRef.resetFields();
    },
    // 表格中编辑按钮的点击事件---包括动态参数和静态属性中的“编辑”按钮
    async showEditDialog(catId, attrId) {
      // console.log(cat_id, attr_id);
      // 请求动态参数或静态属性数据，并将该数据渲染在即将弹出的对话框表单域中
      const { data: res } = await this.$http.get(`categories/${catId}/attributes/${attrId}`, {
        params: { attr_sel: this.activeName }
      });
      console.log(res);
      if (res.meta.status !== 200) {
        return this.$message.error('获取' + this.titleText + '失败!');
      }
      this.$message.success('获取' + this.titleText + '成功！');
      this.editRuleForm = res.data;
      console.log(this.editRuleForm);
      // 弹出对话框
      this.editDialogVisible = true;
    },
    // 动态参数和静态属性中，编辑 按钮点击弹出的对话框的关闭事件
    resetEditDialog() {
      this.$refs.editFormRef.resetFields();
    },
    // 编辑 按钮点击时，编辑框 预校验
    editFormPre() {
      this.$refs.editFormRef.validate(async valid => {
        // console.log(valid);
        if (!valid) return;
        // 预校验成功
        // 1.发起请求，提交编辑参数的更改
        const { data: res } = await this.$http.put(`categories/${this.catId}/attributes/${this.editRuleForm.attr_id}`, {
          // 更新的内容在attr_name中
          attr_name: this.editRuleForm.attr_name,
          attr_sel: this.editRuleForm.attr_sel,
          attr_vals: this.editRuleForm.attr_vals
        });
        console.log(res);
        // 关闭对话框
        this.editDialogVisible = false;
        if (res.meta.status !== 200) {
          return this.$message.error('编辑' + this.titleText + '失败!');
        }
        // 重新渲染一下动态参或静态属性列表
        this.getParamsData();
        return this.$message.success('编辑' + this.titleText + '成功!');
      });
    },
    // newTag 新建tag标签的相关事件处理函数
    async saveAttrVals(row) {
      const { data: res } = await this.$http.put(`categories/${this.catId}/attributes/${row.attr_id}`, {
        attr_name: row.attr_name,
        attr_sel: row.attr_sel,
        // attr_vals提交参数需要是字符串；使用Array的join方法分割，更新的内容在数组attr_vals中
        attr_vals: row.attr_vals.join(' ')
      });
      console.log(res);
      if (res.meta.status !== 200) {
        return this.$message.error('编辑属性操作失败!');
      }
      return this.$message.success('编辑属性操作成功！');
    },
    handleInputConfirm(row) {
      // console.log('ok');
      const inputValue = row.inputValue;
      if (inputValue) {
        // 为了以防万一，去除合法输入内容的空格
        row.attr_vals.push(inputValue.trim());
        // 提交到后台中
        /*
        请求参数：
        分类id ：当三级分类选择完成，就可以确定，从计算属性catId中获取
        属性id:从作用域插槽该行数据中拿到
        提交参数：
        attr_name:新添加属性的名称
        attr_sel：属性类型 many或者only
        */

        //  删除tag时，也要发起该put请求，将它封装成一个函数saveAttrVals()
        // const { data: res } = await this.$http.put(
        //   `categories/${this.catId}/attributes/${row.attr_id}`,
        //   {
        //     attr_name: row.attr_name,
        //     attr_sel: row.attr_sel,
        //     // 更新的内容在数组attr_vals中
        //     attr_vals: row.attr_vals.join(' ')
        //   }
        // );
        // console.log(res);
        // if (res.meata.status !== 200)
        //   return this.$message.error('添加属性操作失败!');
        // return this.$message.success('添加属性操作成功！');

        // Tag标签的添加
        this.saveAttrVals(row);
      }
      // newTag中没有输入任何内容，new Tag恢复原状即可：a.重绘成按钮 b.清空文本
      row.inputVisible = false;
      row.inputValue = '';
    },
    // 显示文本输入框的操作
    // inputVisible值设定为true,待文本框渲染完成后，获取焦点，input原生的focus()方法
    showInput(row) {
      row.inputVisible = true;
      // $nextTick()方法的作用，是当页面中元素被重新渲染后，才执行方法中回调
      this.$nextTick(_ => {
        this.$refs.saveTagInput.$refs.input.focus();
      });
    },
    // Tag标签的删除
    handleClose(index, row) {
      // 从索引index开始，删除元素个数为1，即：原数组中索引为index的那个元素被删除
      row.attr_vals.splice(index, 1);
      this.saveAttrVals(row); // 更新数据
    },
    // 表格中【删除】按钮点击事件
    async deleteData(row) {
      const result = await this.$messageBox
        .confirm('此操作将永久删除该文件, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })
        .catch(error => error);
      console.log(result);
      // result='cancle'表示点击了取消按钮
      // result='confirm'表示点击了确定按钮
      if (result !== 'confirm') return this.$message.error('删除操作已取消!');
      // 确定要删除数据---delete请求
      const { data: res } = await this.$http.delete(`categories/${this.catId}/attributes/${row.attr_id}`);
      // console.log(res.data);//删除成功res.data为null
      if (res.meta.status !== 200) return this.$message.error('删除请求失败!');
      // 重新渲染动态参数或静态属性列表
      this.getParamsData();
      return this.$message.success('成功删除该条数据!');
    }
  }
};
</script>

<style lang="less" scoped>
.cateParams_container {
  .cat-opt {
    margin: 15px 0;
    .col_left {
      text-align: left;
    }
  }
  // tabs标签页中按钮el-row下边距
  .para_attr {
    margin-bottom: 15px;
  }
  // Tag标签组件的外边距
  .el-tag {
    margin: 10px;
  }
  // new Tag的左边距
  .button-new-tag {
    margin: 0 10px;
  }
  // 当点击new Tag要输入内容时的输入文本框样式控制
  .input-new-tag {
    width: 90px;
    margin-left: 10px;
    vertical-align: center;
  }
}
</style>
